Recent Changes - Search:

Home & News

Organization

Assignments

Support

edit SideBar

Lab3

General Remarks

  • We suggest to read the following tutorials before you start implementing:
    • Study the JacORB Programming Guide. Specifically chapters 4 and 5 are interesting for this lab. You can find it in the JacORB distribution in doc/ProgrammingGuide.pdf.
    • The JacORB bank demo shows how to work with implicit transactions and is a good reference for this lab. You can find it in the JacORB distribution in demo/bank/transaction/implicit.
    • IDL overview: Provides a good overview over the Interface Definition Language.
    • Java IDL Mapping: Describes the mapping from IDL to Java.
    • Java CORBA Introduction: This is a nice introduction for using CORBA with Java. Note that it's not JacORB specific!
  • Group work is NOT allowed in the lab. You have to work alone. Discussions with colleagues (e.g., in the forum) are allowed but the code has to be written alone.
  • Be sure to check the Tricky Parts section for questions!

Submission Guide (for all Labs)

Submission

  • You must upload your solution using the Teaching Tool before the submission deadline: 15.01., 18:00 cet. - the deadline is hard! You are responsible for submitting your solution in time. If you do not submit, you won't get any points!
  • Upload your solution as a ZIP file. Please submit only the sources including your build and idl file (see below) of your solution (not the compiled class files and no third-party libraries).
  • Your submission must compile and run in our lab environment. Use and complete the provided ant template.
  • Before the submission deadline, you can upload your solution as often as you like. Note that any existing submission will be replaced by uploading a new one.
  • Please make sure that your upload was successful (i.e., you should be able to download your solution - as the tutors will do during the interview).

Interviews

  • After the submission deadline, there will be a mandatory interview (Abgabegespräch). You must register for a time slot to the interviews using the Teaching Tool.
  • You can do the interview only if you submitted your solution before the deadline!
  • The interview will take place in the DSLab. During the interview, you will be asked about the solution that you uploaded (i.e., changes after the deadline will not be taken into account!). In the interview you need to explain your code, design and architecture in detail.
  • Remember that you can do the interview only once!

Description

In this assignment you will learn:

  • the basics of CORBA (Common Object Request Broker Architecture)
  • how to write a CORBA solution by starting with an IDL (Interface Description Language)
  • how to generate Java artifacts from CORBA
  • how to implement simple CORBA objects and clients
  • how to use implicit transactions in CORBA

Overview

CORBA objects are hosted by server applications that provide one or more object instances to clients. The communication of both the client and the server is done by using so called ORBs (Object Request Brokers) that deal with marshaling (encoding arguments in a platform independent-format) and unmarshaling (decoding platform-independent data type representations into platform specific formats) and invocation of CORBA operations. One primary advantage of CORBA compared to other technologies such as RMI, .NET Remoting, or Web services is its coverage of services. That is, CORBA supports the full set of additional services that are required in most distributed system environments such as naming and trading, transaction and synchronization, notification and security services.

In this assignment we will use CORBA to implement a short messaging service (sms) infrastructure for telephone companies (telcos). Since it must be possible for customers of one telco to send messages to customers of other telcos, these telcos must be able to communicate with each other. Each telco can have its own IT infrastructure, possibly implemented in different languages on different platforms. Therefore, a standard communication technology has to be used for integrating these heterogeneous solutions. We choose CORBA to realize such a telco system.

Domain assumptions:

  • A telco is a telephone company which provides its customers a service to send short messages. Each telco has a name and its own unique prefix which consists of several digits (but at least one) (e.g. "0664").
  • Messages contain text of arbitrary length (quite contradictory to sms, but not relevant for our purpose) and get a timestamp on sending. Messages may be sent to multiple recipients, who may be customers of different telcos.
  • A telco internal number is a telephone number that is only unique within a telco's scope and consists of several digits (but at least one) (e.g. "123456"). A full number is a telephone number that is unique accross telcos, i.e., it consists of a prefix and a telco internal number (e.g. "0664/123456").
  • Customer authentication is based on the telco internal number together with a four digit PIN code.

Architectural considerations:
In this assignment we won't have such a simple client-server-architecture as before. Instead there might be several different telcos, that have to communicate with other telcos over a well defined, public interface and with their clients over a telco specific interface.

So each telco has to serve two purposes: on the one side it has to deal with messages sent by its own customers and potentially has to forward it to other telcos, on the other side it must be able to handle messages coming from other telcos and forward them to its own customers.

So customers may login, logout and send messages using the internal interface of their telco. "Internal" in this context means "telco internal", therefore this communication could be handled using any possible protocol or implemented in any programming language (we will also use CORBA and Java for this).
It first gets exciting when the telco server has to communicate with other telcos (for example if a recipient of a message is not a customer of the sender's telco) over a well defined public interface, that each telco has to support. To make it even more interesting, the delivery of the message to all recipients must be handled within an (implicit) CORBA transaction, i.e., either all recipients receive the message, or none.
To sum it up, each telco has an internal interface for serving its own customer requests, and an external interface for forwarding incoming messages to its own customers.

So when a message is received on a telco, it has to deliver the message to the recipients. If the concerned recipient is currently online, the telco has to immediately forward it (therefore we need client callbacks again), otherwise it has to store it temporarily and transmit it the next time the recipient goes online. However, it's not necessary to store the state persistently when the telco is shut down.

As already said in the last assignment, most distributed object frameworks provide a naming service, which allows binding/looking up remote references to/by simple names. CORBA provides one (org.omg.CosNaming.NamingContextExt), and we will use it for binding telco references to their prefixes, allowing customers to find their telco and telcos to find other telcos. As you will see this happens quite similar as with the java.rmi.registry.Registry in RMI.

The following figure shows an example scenario:

Figure 1: Telco Architecture

All operations displayed in red have to be executed within one single transaction (started in 7'), the one shown using a dashed line is a notification (thus called on the client callback object). The mailbox itself is not a stand-alone communication partner (such as client or server) - it's meant as a server-side data structure for storing missed messages of a single customer (anyway, you may implement this requirement however you want). Please note that the order of some operations (e.g. 9/10/11) is interchangeable and solely depends on your implementation decisions.

Server

In this assignment the server is simply a specific implementation of a telco. It allows customers to login, send sms and logout, as well as other telcos to transmit messages to this telco's recipients.

Arguments

Your server program shall expect exactly one argument (if missing, print a usage message and exit):

  • fileName: specifies the name for a properties file that can be found on the classpath.

The properties file then should be read in from the classpath (see the hint section for details). The format of properties file looks like the following:


#prefix for the telco, also used for binding it to name service
prefix:0664
#name of the telco
name:B2
#customer data follows (telco internal number:pin pairs):
123456:1234
234567:2345
345678:3456
...


An example file is provided and can be downloaded here. It contains the prefix (which shall be used for binding the telco object) and name of the telco to be started, as well as all customer data in form of telco internal number and pin code pairs. You can expect that there's no other text in it, so simply filter out the prefix and name and then read all accounts.

Interfaces

In CORBA you always have to define your interfaces in IDL files, thus, create the file telco.idl in your source folder (the ant template provided expects this path and name) and specify your interfaces, data structures etc. there. This specification is platform neutral and can be translated by IDL compilers to platform specific code (in our case: Java).

Public telco interface
This is the interface every telco has to implement to assure compatibility with other telcos. Normally, this interface would be given to you by some standardization group, but for our lab you also have to define it.

Required functionality:

  • Get the name of the telco.
  • Get the prefix of the telco.
  • Deliver message within a transaction:
    Allows other telcos to submit messages (consisting of text, the sender's full number and sending timestamp) to one or several recipients of this telco (in form of telco internal numbers). The telco has to forward the message to all online recipients and store it temporarily for offline recipients. However, both ways must be implemented transaction aware (see this for help)! In case a recipient is unknown or any internal error occurs the telco may raise an exception.

Internal telco interface
Extend the public interface to implement your own telco service. For any operation but login the client must be already logged in - you can check this either by using a session identifier or by letting the client submit its user name and password for each operation).

Required functionality:

  • Login of a customer:
    The client/customer has to supply its telco internal number, pin code and a callback object (see client description). The server has to check whether the submitted values are valid and return all missed messages.
  • Logout of a customer:
    From now on the server has to store any incoming message for this customer until the next time he/she goes online.
  • Send message as a single transaction:
    Lets the client send a message. The server has to create a transaction, possibly deliver the message to other telcos, possibly store the message for its own offline recipients and deliver it to its own online recipients. In case of any error (such as unknown number, unknown telco prefix or any failure, also of other telcos) the transaction must be rolled back, otherwise committed. You shall use the implicit transaction propagation model as described here. Note that also the sender may be a recipient.
Implementation details

On startup you first have to read in the properties file. Then create your telco object, make it remotely available by exporting it and bind it to the naming service using a NameComponent containing the prefix as id and "telco" as kind.

When a customer wants to send a message, your telco implementation has to create a transaction (see the JacORB bank example). Then it has to map recipients to telcos (using the full number's prefix) and look up the telcos in the name service (again by supplying the prefix). You shall cache already looked up telco references to avoid unnecessary lookups. If any problem occurs (such as telco could not be found in name service, telco does not know recipient number), you have to rollback the transaction, otherwise commit it. Note that also already looked up telcos might have gone offline - if a org.omg.CORBA.TRANSIENT or org.omg.CORBA.COMM_FAILURE exception occurs you may assume the telco is not reachable and have to rollback the transaction.

When the telco itself is part of a transaction (either when called by another telco or when a recipient of a message sent by an own customer is also an own customer), you first have to check whether such a number is known. If not, throw an appropriate exception (which will cause the transaction to rollback). If the recipient is currently online you have to transmit the message directly over the client callback (see below), otherwise store the message. Clients may also go offline without informing the server appropriately (for example if the computer crashes or the connection is lost). You don’t have to detect this at once, but the next time the server is trying to contact the client to deliver a message: if a org.omg.CORBA.TRANSIENT or org.omg.CORBA.COMM_FAILURE exception occurs you may assume the client is offline. Therefore update the client's state and store the message to deliver it the next time the client goes online again.

As in the last assignment the telco has to manage state across several threads (they are managed by JacORB transparently). This again makes synchronization necessary when accessing your shared data structures!

If your server is ready for handling requests print “Server <prefix> up. Hit enter to exit.” to the console and implement this behavior. On exit unbind the telco corba object from the naming service and also call ORB.shutdown(), otherwise your program might not shut down – again you must not use System.exit().

Client

In this part you have to build an interactive command line client application for your telco implementation.

Arguments

Again only one argument has to be specified (if missing, print a usage message and exit):

  • prefix: the prefix of the telco to contact. The supplied value will be used for resolving the telco object in the naming service.
Callback interface

As you've already noticed, a telco has to inform its online recipients immediately on incoming messages. If you've solved the last assignment, you are already familiar with the callback concept - in CORBA it basically works exactly the same way as in RMI. To make it short: you have to define an interface in your IDL file (telco.idl) which your client has to implement.

Required functionality:

  • Receive message within a transaction:
    This method can be called by the telco to inform the client about a message. The client has to output the message to the console, containing the sending time, the sender's full number and the text (e.g. "20.10.2008 @ 12:01 | 0664/123456: This is a test message."). Please note that the client notification must also be part of the CORBA transaction originally issued by the sender's telco.
Implementation details

On startup of your program you first have to look up your telco in the name service using the specified prefix. Note that you can only cast the looked up org.omg.CORBA.Object instance by using the *Helper.narrow() method. If the telco was looked up successfully print "Contacted telco "<telcoName>" (<telcoPrefix>) successfully." to the console. Afterwards export your client callback object like you exported your telco server object. The only difference is that you should not bind it to the name service, but instead simply pass it as parameter for the login command.

Interactive commands

The following commands must be supported by your client application. Take care of handling invalid commands and arguments and provide usage messages in these cases. Print meaningful error messages whenever the server throws an “expected” exception (such as “Invalid login data.” when trying to login with an invalid number/pin combination). Also print success messages if an operation was executed successfully.
Note that you first have to login before sending sms (and, obviously, before logging out).

  • login <telcoInternalNumber> <pin>
    Logs the user in. The telco server has to return all missed messages. The output should include the same information as displayed below:
    :> login 123456 1234
    Logged in successfully.
    Missed messages:
          20.10.2008 @ 12:01 | 0699/123456: This is a test message.
          20.10.2008 @ 12:05 | 0699/123456: This is also an extremely exciting test message.
  • logout
    Logs out the currently logged in user.
  • sendSms "<text>" [<telPrefix>/<telNumber>]+
    Sends an sms containing the specified text (all text between (exclusive) the first two occuring quotes)) to a list (containing at least one) of space separated recipients (in form of full numbers in the specified format).
    :> sendSms "This is a test message." 0664/123456 0664/234567
    Message sent successfully.
  • stop
    Stops the client application. If a user is currently logged in you have to log it out implicitly. Again you may not use System.exit(), but have to orderly close all acquired resources (shut down the ORB).

Ant template

As in the last assignment we provide a template build file (build.xml) in which you only have to adjust some class names. Put your source into the subdirectory "src", place the *.properties files and telco.idl into the "src" directory and move on the command line to the directory where the build file is located.

Simply type "ant idl-compile" for idl compilation (compiles the telco.idl file) and "ant" for java compilation (this task also copies your .properties files to the build directory).

Type "ant run-server -Dprops=b2" to start a server reading from b2.properties. In the provided build file an argument is expected for the server (<arg value="${props}.properties"/>). By specifying the -Dprops=b2 option, ant actually passes "b2.properties" as an argument to your server.

Type "ant run-client -Dprefix=0664" to start a client that connects to a telco bound to 0664 (by substituting <arg value="${prefix}"/> in the build file by "0664").

Put the src directory including telco.idl and build.xml into your submission.
Note that it's absolutely required that we are able to start your programs with these predefined commands!


Transactions help

How to provide transaction support in your telco/client

As the deliver message operation of the public telco interface and the message received operation of the client callback interface have to be executed within transactions, the following problem arises:
According to the OMG Transaction Service Specfication a resource may only be involved in one transaction at the same time. However, we want our client and especially our telco to be able to receive messages from different transactions concurrently, otherwise the performance would be quite bad.

So don't let your public telco interface and client callback directly extend CosTransaction::Resource and CosTransaction::TransactionalObject, and instead create an additional interface that extends these both and only provides a simple method that takes a message parameter (containing sending time, sender's full number and text).

On the client's side it becomes now simple. Provide an implementation for the specified resource interface, which on commit simply outputs the received message. In your callback you then create a new instance of this for each incoming request, hand over the message, and register it with the coordinator.

On the telco's side it's a bit more complicated, since there might be several recipients that might be online or offline. If a recipient is online - there's no problem, just forward it to the callback object (which handles the transaction as described above). But if we have to store it for a recipient, we also have to consider the transaction semantics. Therefore also provide an implementation for the specified resource interface, which on commit stores the message to the recipient's mailbox. In your telco do the same as on the client's side (create resource, hand over message, register it with coordinator).

For your information:
The CosTransaction::TransactionalObject is just a markup interface and hence has no operations at all (primary a historic relict from previous CORBA standards). However, you have to implement the 5 operations of the Resource interface. You can skip implementing the forget() operation and implement the commit_one_phase() operation as in the JacORB sample. The prepare() method shall return one of the three values Vote.VoteCommit, Vote.VoteRollback, Vote.VoteReadOnly depending if the changes shall be committed, or rolled back. Vote.VoteReadOnly shall be used if there were no changes at all.

Implicit transactions

Using implicit transactions means that transaction contexts storing the current state of a transaction are not directly visible in client or server code but is automatically added by so-called interceptors - in CORBA interceptors hook in requests and may modify the transmitted data such as arguments or may add service contexts such as in our case.

To inform an ORB that it shall use the already predefined interceptor for implicit transactions the following value for the property org.omg.PortableInterceptor.ORBInitializerClass.TSClientInit must be set during the ORB initialization: org.jacorb.transaction.TransactionInitializer. This is a class that registers an object of type org.omg.CosTransactions.Current as an initial reference named TransactionCurrent. This reference can then be retrieved with orb.resolve_initial_references. The provided ant template already sets this property (see the run-server and run-client task).

The begin operation of the org.omg.CosTransactions.Current interface may be used to initiate a transaction. The timeout shall be set to a value of 40. This has to be set before you begin a transaction. After a transaction has begun you can call whatever transaction aware functionality of CORBA objects you want. The transaction context is transmitted implicitly. For rolling back a transaction you have to call the rollback function (surprisingly). Committing the transaction is done via the commit operation (use true as argument). Never kill a server (regardless how) that has started a transaction before the timeout has passed. When you do manual tests you can set the timeout to a smaller value.

From transaction aware objects you have to use the org.omg.CosTransactions.Current interface, too. However, this time you shall receive the org.omg.CosTransactions.Control interface via the Current's get_control() operation. Control supports two different functionalities: returning a Coordinator (with get_coordinator()) and returning a Terminator (with get_terminator()). In transaction aware operations you have to register the transaction aware CORBA object with the coordinator's register_resource() operation. The Resource's operations (prepare, rollback, commit) are then used automatically when the transaction initiator calls commit or rollback. In case of any TransactionServer related exception (example: Inactive) throw the runtime exception org.omg.CORBA.TRANSACTION_ROLLEDBACK. To get the exact syntax of the transaction server related operations take a look at the CosTransactions.idl or study the OMG Transaction Service Specification.

IDL compilation

For compiling your IDL file, which uses transaction service interfaces, you have to

  • write #include <CosTransactions.idl> at the top of your IDL file to include the interface definitions
  • and therefore tell the JacORB IDL compiler where to find the required IDL file <CosTransactions.idl>: Use the -I option (e.g. -I/opt/jacorb/idl/omg/) to do this. If you use our ant template this option is already included (take a look at the idl-compile target).

Hints & Tricky Parts

  • Study the JacORB programmer's guide, in particular chapter 4 - Getting Started - explains how to program a CORBA server and a CORBA client with JacORB. Chapter 5 explains how to access the name service. Chapter 4 contains everything you need to implement your server and client (except the transactional stuff).
  • In order to use JacORB instead of the built-in (and incomplete) ORB of SUN that is provided with Java, you have to provide two arguments to the Java VM with -D:
    • -Dorg.omg.CORBA.ORBClass=org.jacorb.orb.ORB and
    • -Dorg.omg.CORBA.ORBSingletonClass=org.jacorb.orb.ORBSingleton. You also have to include all the JacORB JAR files (located in the lib directory of the JacORB installation) into the CLASSPATH. Instead of manually applying these settings, you can also use the jaco shell script that is located in the $JACORB_HOME/bin directory. This script invokes Java with the appropriate VM arguments and classpath settings.
      We suggest using the provided ant template, which already includes these settings.
  • JacORB services:
    You will need to start the naming and transaction service to accomplish this task. All described service commands are located in the $JACORB_HOME/bin directory. We recommend using the predefined tasks of the provided ant template which clearly simplify the configuration and startup of these services.
    • Naming service:
      You need the naming service to bind and lookup your CORBA objects (this is quite similar to the RMI registry from the last lab).
      Usage: ns -Djacorb.naming.ior_filename=$HOME/NS_REF or ant run-ns
      If you don't use the provided ant target, you have to copy the jacorb_properties.template from $JACORB_HOME/etc to the directory where you execute your servers/clients and rename it to jacorb.properties. Then edit the ORBInitRef.NameService entry and set it to the appropriate path (e.g. ORBInitRef.NameService=file:///dslab/home/dslab/dslabXXX/NS_REF), so your programs are able to locate the naming service. There you can also edit a lot of other configuration parameters when invoking JacORB, although you don't have to.
    • Transaction service:
      You first have to start the naming service as described above.
      Usage: ts -ORBInitRef NameService=file://$HOME/NS_REF or ant run-ts
    • Naming manager:
      If you are working at home (this one's a GUI application) you can use this tool to view the objects bound to the naming service. This is helpful if you are unsure about your binding code (the transaction service is also visible there if it was started successfully).
      Usage: nmg -ORBInitRef NameService=file://$HOME/NS_REF or ant run-nmg
  • Using JacORB at home:
    • Download JacORB. If you want to build the JacORB API documentation (see below) you have to select the source distribution, otherwise the binary one is sufficient.
    • Set the environment entry $JACORB_HOME.
    • If you don't want to use the predefined ant targets you have to call "ant jaco" in JACORB_HOME and should include $JACORB_HOME/bin into your $PATH variable.
  • Reading in a properties file from the classpath (without exception handling):
    java.io.InputStream is = ClassLoader.getSystemResourceAsStream("b2.properties");
    if (is != null) {
    java.util.Properties props = new java.util.Properties();
    try {
    props.load(is);
    String prefix = props.getProperty("prefix");
    ...
    } finally {
    is.close();
    }
    } else {
    System.err.println("Properties file not found!");
    }
  • Submitting dates in CORBA: simply pass the time value as returned by java.util.Date.getTime() and reconstruct the date using the java.util.Date(long time) constructor. Note that a long in Java is equivalent to a long long in the IDL.

Further Reading Suggestions

  • APIs:
  • Specifiations
    • OMG CORBA Specification: This is the original OMG CORBA Specification. You can use it as a reference if you are specially interested in CORBA.
    • OMG Transaction Service Specfication: This is the original OMG Transaction Service Specification. In general, it is not necessary to read all of this. However, in Section 2 all involved CORBA interfaces are explained (as Resource, Control, Coordinator, Terminator).
    • OMG IDL to Java Mapping Specification: The official OMG document about the mapping from IDL to Java.
  • Tutorials:
    • CORBA Callbacks: Simple tutorial for callbacks (not JacORB specific).
    • Java CORBA Guide: Here you can find several informations about CORBA with Java; again this is not related to using JacORB.
  • Proposed Literature:
    • Advanced CORBA(R) Programming with C++ by by Michi Henning and Steve Vinoski
Edit - History - Print - Recent Changes - Search
Page last modified on December 07, 2008, at 05:09 PM CET